#!/usr/local/bin/python
"""This file is runing on remote node."""
from SimpleXMLRPCServer import SimpleXMLRPCServer
#from service.PlusterLog import *
#Note: the Node.py shoud support python 2.2 so I have to
#remove all logging modules
from service.pconfig import PConfig
from service.exception import *
from localEnv import *
import xmlrpclib
import threading
import time
import os
import re
import socket
#TODO fix me. in python 2.2 re do not support re.M kind of things
import sys
import traceback
import signal
import random
def sig_handler (sig, frame):
    """ Hanle ctrl c signal"""
    print "Close Node"
    sys.exit(0)

class Node:
    """Work as an agent on remote node.Register itself to MainServer
    and Run remote task.The instance will register to XMLRPC server.so
    methods must return a value"""
    def __init__(self,name,net,ip,mac,port):
        #PlusterLog.__init__(self)
        #self.log.info("Remote Node initialize")
        self.name=name
        self.net=net
        self.ip=get_ip(net) #TODO:fix me. read config
        self.mac=get_mac(net)
        self.port=port #Note unlike other attribute. port is int
        self.taskList=[]
        self.ps=get_ps()
        self.cpu_num,self.hz,self.cpu_type=get_cpu()
        self.next_id=0 #task id counter
        self.stat = "run" #run stop restart
        self.time_out = 600 #restart time out
        print "Node Name:",str(self.name)
        print "Node IP: ",self.ip,"Port: ",self.port
        print "CPU: ",self.cpu_type
        print "CPU number: ",self.cpu_num

    def is_alive (self):
        """ if Node is still running. return True
        Otherwise NodeDocument will handle exception"""
        return True

    def keep_alive (self):
        """Main server call this to keep remote node alive """
        self.stat='run'
        return 0

    def restart (self, time_out):
        """ Reconnect main server after tiemout second"""
        self.time_out = time_out
        self.stat = 'restart'
        return 0

    def stop(self):
        """ Stop Node"""
        self.stat='stop'
        return 0

    def update_ps(self):
        self.ps=get_ps()
        return 0

    def is_running_user(self,name):
        """Return a bool.Is there any running program of that user?"""
        if self.ps.find(name): #Maybe too simple. but just work
            return True
        else:
            return False

    def get_name(self):
        return self.name

    def get_ip(self):
        return self.ip

    def get_mac(self):
        return self.mac

    def get_port(self):
        return self.port

    def get_cpu_info(self):
        return (self.cpu_num,self.hz,self.cpu_type)

    def get_mem_info(self):
        return get_mem('MemTotal')

    def get_disk_space(self):
        return get_disk()

    def get_usage(self):
        "return whole system cpu mem in and out"
        cpu,mem=cpu_mem_usage(self.ps)
        cpu/=self.cpu_num
        i,o=get_net_io(self.net)
        #print i,o
        print "Update Node Cpu %f Mem %f In %s Out %s"%(cpu,mem,i,o)
        return cpu,mem,i,o

    def get_user_usage(self,name):
        "return user based cpu and memory"
        #ps=get_ps()
        cpu,mem=get_user_cpu_mem_usage(name,self.ps)
        cpu/=self.cpu_num
        print "Update user %s cpu %f mem %f"%(name,cpu,mem)
        return cpu,mem

    def GetInfo(self):
        """Return name,ip and mac of current node"""
        return self.name,self.ip,self.mac

    def load_remote_task(self,name,ip,port,arg):
        """Load Task from file in /tasks/Remote directory except
            ImportError After LoadTask we could use class object
            self.Task,self.View, self.Adapter."""
        try:
            print("Node LoadTask : %s"%name)
            task_pkg=__import__("tasks."+name)
            task_module=task_pkg.__dict__[name]
            task_class=task_module.__dict__[name+"Task"]
            atask=task_class(ip,port,arg)
            atask.start()

        except ImportError:
            print("Import error check your remote task file")
            raise
        except KeyError:
            print("Key error check your class name in task file. See manual for how to name a task in a right way")
        except RfileNoFileError:
            return -1


    def RunTask(self,address,port,arg):
        """Called from out side to run task on remote node
        address=url for return
        port=port for url
        arg=parameter dirve the task"""
        print("Node Run Task")
        newTask=self.Task(address,port,arg)
        self.taskList.append(newTask)
        newTask.start()
        return 0

class NodeServer(threading.Thread):
    def __init__(self,node):
        threading.Thread.__init__(self)
        self.node=node
        try:
            self.nodeServer=SimpleXMLRPCServer((node.get_ip(), node.get_port()),allow_none=True)
            self.nodeServer.register_instance(self.node)
        except socket.error:
            print "Port %d has been used.Exit"%node.get_port()
            sys.exit()
    def run(self):
        while self.node.stat!='stop':
            self.nodeServer.handle_request()

if __name__=='__main__':
    #TODO This part should check again and move into
    #test folder
    signal.signal(signal.SIGINT,sig_handler)
    signal.signal(signal.SIGTERM,sig_handler)
    cfg=PConfig()
    net=cfg.node_net
    port=cfg.node_port
    ip=get_ip(net)
    mac=get_mac(net)
    #here use the last digit of ip as name so I can draw it easily
    name=ip.split('.')[3]
    node=Node(name,net,ip,mac,port)
    nodeName=node.get_name()
    ip=node.get_ip()
    port=node.get_port()
    print "Pluster Node Name: %s Start ... "%nodeName
    # Create server
    nodeServer=NodeServer(node)
    nodeServer.setDaemon(True)
    nodeServer.start()
    #We should wait for a random seconds,to prevent all node
    #connect main server together
    #Since randint use time as seed, We should jumpahead from the first state, To make randit more *random*
    random.jumpahead(random.randint(1,100))
    wait_time=random.randint(1,20)
    print"Wait for %d sencods to prevent conflict with other node"%wait_time
    time.sleep(wait_time)
    try:
        main_addr=cfg.ms_address
        main_port=cfg.ms_port
        connect='http://'+main_addr+':'+str(main_port)
        print "Connecting:",connect
        mainServer=xmlrpclib.Server(connect)
        print 'http://'+ip+':'+str(port)
        mainServer.RegisterNode('http://'+ip+':'+str(port))
    except socket.error:
        print 'Can not connect main server. Try again after 30s'
        time.sleep(random.randint(10,50))
        try:
            print "Connecting:",connect
            mainServer=xmlrpclib.Server(connect,allow_none=True)
            print 'http://'+ip+':'+str(port)
            mainServer.RegisterNode('http://'+ip+':'+str(port))
        except socket.error:
            print 'Can not connect main server. Exit'
            exit(0)



    while node.stat=='run':
        node.stat="wait"
        time.sleep(node.time_out)
        if node.stat=='wait' or node.stat=='stop':
            break

    exit(0)

